import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'dart:ui' as ui;

import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/scroll_extensions.dart';
import 'package:immich_mobile/pages/common/download_panel.dart';
import 'package:immich_mobile/pages/common/gallery_stacked_children.dart';
// import 'package:immich_mobile/pages/common/native_video_viewer.page.dart';
import 'package:immich_mobile/providers/app_settings.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/asset_stack.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/is_motion_video_playing.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart';
//import 'package:immich_mobile/providers/cast.provider.dart';
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
import 'package:immich_mobile/services/app_settings.service.dart';
import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart';
import 'package:immich_mobile/widgets/asset_viewer/advanced_bottom_sheet.dart';
import 'package:immich_mobile/widgets/asset_viewer/bottom_gallery_bar.dart';
import 'package:immich_mobile/widgets/asset_viewer/detail_panel/detail_panel.dart';
import 'package:immich_mobile/widgets/asset_viewer/gallery_app_bar.dart';
import 'package:immich_mobile/widgets/common/immich_image.dart';
import 'package:immich_mobile/widgets/common/immich_thumbnail.dart';
import 'package:immich_mobile/widgets/photo_view/photo_view_gallery.dart';
import 'package:immich_mobile/widgets/photo_view/src/photo_view_computed_scale.dart';
import 'package:immich_mobile/widgets/photo_view/src/photo_view_scale_state.dart';
import 'package:immich_mobile/widgets/photo_view/src/utils/photo_view_hero_attributes.dart';

import 'package:immich_mobile/main.dart';
import 'package:immich_mobile/pages/common/video_viewer.page.dart';
import 'package:immich_mobile/utils/cache/custom_image_cache.dart';

int imageHdrState = -1;
int lastPlayingState = 0;

@RoutePage()
// ignore: must_be_immutable
/// Expects [currentAssetProvider] to be set before navigating to this page
class GalleryViewerPage extends HookConsumerWidget {
  final int initialIndex;
  final int heroOffset;
  final bool showStack;
  final RenderList renderList;

  GalleryViewerPage({
    super.key,
    required this.renderList,
    this.initialIndex = 0,
    this.heroOffset = 0,
    this.showStack = false,
  }) : controller = PageController(initialPage: initialIndex);

  final PageController controller;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final totalAssets = useState(renderList.totalAssets);
    final isZoomed = useState(false);
    final stackIndex = useState(0);
    final localPosition = useRef<Offset?>(null);
    final currentIndex = useValueNotifier(initialIndex);
    final loadAsset = renderList.loadAsset;
    final isPlayingMotionVideo = ref.watch(isPlayingMotionVideoProvider);
    //final isCasting = ref.watch(castProvider.select((c) => c.isCasting));

    final videoPlayerKeys = useRef<Map<int, GlobalKey>>({});

    GlobalKey getVideoPlayerKey(int id) {
      videoPlayerKeys.value.putIfAbsent(id, () => GlobalKey());
      return videoPlayerKeys.value[id]!;
    }

    final shouldLoopVideo = useState(AppSettingsEnum.loopVideo.defaultValue);

    final routeAware = useMemoized(() => _MyRouteAware());
    final imageListener = useRef<ImageStreamListener?>(null);
    final currentImageProvider = useRef<ImageProvider?>(null);
    final timers = useRef<List<Timer>>([]);
    final cancelAllTimers = useCallback(() {
      for (final timer in timers.value) {
        if (timer.isActive) timer.cancel();
      }
      timers.value.clear();
    }, []);

    useEffect(() {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        final modalRoute = ModalRoute.of(context);
        if (modalRoute is PageRoute) {
          routeObserver.subscribe(routeAware, modalRoute);
        }
      });

      return () {
        routeObserver.unsubscribe(routeAware);
      };
    }, [context]);

    Future<void> precacheNextImage(int index) async {
      if (!context.mounted) {
        return;
      }

      void onError(Object exception, StackTrace? stackTrace) {
        // swallow error silently
        log.severe('Error precaching next image: $exception, $stackTrace');
      }

      try {
        if (index < totalAssets.value && index >= 0) {
          final asset = loadAsset(index);
          await precacheImage(
            ImmichImage.imageProvider(asset: asset, width: asset.width!.toDouble(), height: asset.height!.toDouble()),
            context,
            onError: onError,
          );
        }
      } catch (e) {
        // swallow error silently
        log.severe('Error precaching next image: $e');
        context.maybePop();
      }
    }

    void getImageColorSpace(ImageProvider provider, BuildContext context) async {
      if (imageListener.value != null && currentImageProvider.value != null) {
        currentImageProvider.value!.resolve(ImageConfiguration.empty).removeListener(imageListener.value!);
      }

      ImageStream stream = provider.resolve(ImageConfiguration.empty);

      imageListener.value = ImageStreamListener((ImageInfo info, bool synchronousCall) {
        if (info.image.colorSpace == ui.ColorSpace.extendedSRGB) {
          ui.SetHdr.setHdrMode(hdr: 1, is_image: true);
          imageHdrState = 1;
        } else {
          ui.SetHdr.setHdrMode(hdr: 0, is_image: true);
          imageHdrState = 0;
        }
      }, onError: (_, __) {});

      currentImageProvider.value = provider;
      stream.addListener(imageListener.value!);
    }

    void setDisplayMode(ImageProvider provider, BuildContext context) async {
      getImageColorSpace(provider, context);
    }

    useEffect(() {
      if (ref.read(showControlsProvider)) {
        SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
      } else {
        SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
      }

      // Delay this a bit so we can finish loading the page
      Timer(const Duration(milliseconds: 400), () {
        precacheNextImage(currentIndex.value + 1);
      });

      return null;
    }, const []);

    /*
    useEffect(() {
      final asset = loadAsset(currentIndex.value);

      if (asset.isRemote) {
        ref.read(castProvider.notifier).loadMediaOld(asset, false);
      } else {
        if (isCasting) {
          WidgetsBinding.instance.addPostFrameCallback((_) {
            if (context.mounted) {
              ref.read(castProvider.notifier).stop();
              context.scaffoldMessenger.showSnackBar(
                SnackBar(
                  duration: const Duration(seconds: 1),
                  content: Text(
                    "local_asset_cast_failed".tr(),
                    style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor),
                  ),
                ),
              );
            }
          });
        }
      }
      return null;
    }, [ref.watch(castProvider).isCasting]);
*/

    void showInfo() {
      final asset = ref.read(currentAssetProvider);
      if (asset == null) {
        return;
      }
      showModalBottomSheet(
        shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15.0))),
        barrierColor: Colors.transparent,
        isScrollControlled: true,
        showDragHandle: true,
        enableDrag: true,
        context: context,
        useSafeArea: true,
        builder: (context) {
          return DraggableScrollableSheet(
            minChildSize: 0.5,
            maxChildSize: 1,
            initialChildSize: 0.75,
            expand: false,
            builder: (context, scrollController) {
              return Padding(
                padding: EdgeInsets.only(bottom: context.viewInsets.bottom),
                child: ref.watch(appSettingsServiceProvider).getSetting<bool>(AppSettingsEnum.advancedTroubleshooting)
                    ? AdvancedBottomSheet(assetDetail: asset, scrollController: scrollController)
                    : DetailPanel(asset: asset, scrollController: scrollController),
              );
            },
          );
        },
      );
    }

    void handleSwipeUpDown(DragUpdateDetails details) {
      const int sensitivity = 15;
      const int dxThreshold = 50;
      const double ratioThreshold = 3.0;

      if (isZoomed.value) {
        return;
      }

      // Guard [localPosition] null
      if (localPosition.value == null) {
        return;
      }

      // Check for delta from initial down point
      final d = details.localPosition - localPosition.value!;
      // If the magnitude of the dx swipe is large, we probably didn't mean to go down
      if (d.dx.abs() > dxThreshold) {
        return;
      }

      final ratio = d.dy / max(d.dx.abs(), 1);
      if (d.dy > sensitivity && ratio > ratioThreshold) {
        context.maybePop();
      } else if (d.dy < -sensitivity && ratio < -ratioThreshold) {
        showInfo();
      }
    }

    useEffect(() {
      final a = loadAsset(currentIndex.value);
      final ImageProvider provider = ImmichImage.imageProvider(asset: a);
      ui.SetHdr.enableHdr(enable_hdr: true);
      if (a.isImage) {
        ui.SetHdr.setHdrMode(hdr: 0, is_image: true);
        setDisplayMode(provider, context);
      } else {
        ui.SetHdr.setHdrMode(hdr: 0, is_image: true);
        ui.SetHdr.setHdrMode(hdr: -1, is_image: false);
      }

      if (ref.read(showControlsProvider)) {
        SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
      } else {
        SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
        //SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
      }
      //isPlayingVideo.value = false;
      return () {
        if (imageListener.value != null && currentImageProvider.value != null) {
          currentImageProvider.value!.resolve(ImageConfiguration.empty).removeListener(imageListener.value!);
        }
        if (imageCache is CustomImageCache) {
          (imageCache as CustomImageCache).clearLargeCache();
        }

        //controller.dispose();
        currentImageProvider.value = null;
        imageListener.value = null;
        cancelAllTimers();
      };
    }, []);

    useEffect(() {
      // No need to await this
      unawaited(
        // Delay this a bit so we can finish loading the page
        Future.delayed(const Duration(milliseconds: 400)).then(
          // Precache the next image
          (_) => precacheNextImage(currentIndex.value + 1),
        ),
      );
      return null;
    }, []);

    PhotoViewGalleryPageOptions buildImage(Asset asset) {
      return PhotoViewGalleryPageOptions(
        onDragStart: (_, details, __, ___) {
          localPosition.value = details.localPosition;
        },
        onDragUpdate: (_, details, __) {
          handleSwipeUpDown(details);
        },
        onTapDown: (_, __, ___) {
          ref.read(showControlsProvider.notifier).toggle();
        },
        onLongPressStart: asset.isMotionPhoto
            ? (_, __, ___) {
                ui.SetHdr.setHdrMode(hdr: 0, is_image: true);
                ref.read(isPlayingMotionVideoProvider.notifier).playing = true;
                ui.SetHdr.setHdrMode(hdr: -1, is_image: false);
                lastPlayingState = 1;
              }
            : null,
        imageProvider: ImmichImage.imageProvider(asset: asset),
        heroAttributes: _getHeroAttributes(asset),
        filterQuality: FilterQuality.high,
        tightMode: true,
        initialScale: PhotoViewComputedScale.contained * 0.99,
        minScale: PhotoViewComputedScale.contained * 0.99,
        errorBuilder: (context, error, stackTrace) => ImmichImage(asset, fit: BoxFit.contain),
      );
    }

    PhotoViewGalleryPageOptions buildVideo(BuildContext context, Asset asset) {
      return PhotoViewGalleryPageOptions.customChild(
        onDragStart: (_, details, __, ___) => localPosition.value = details.localPosition,
        onDragUpdate: (_, details, __) => handleSwipeUpDown(details),
        heroAttributes: _getHeroAttributes(asset),
        filterQuality: FilterQuality.high,
        initialScale: PhotoViewComputedScale.contained * 0.99,
        maxScale: 1.0,
        minScale: PhotoViewComputedScale.contained * 0.99,
        basePosition: Alignment.center,
        child: SizedBox(
          width: context.width,
          height: context.height,
          // child: NativeVideoViewerPage(
          //   key: getVideoPlayerKey(asset.id),
          //   asset: asset,
          //   image: Image(
          //     key: ValueKey(asset),
          //     image: ImmichImage.imageProvider(
          //       asset: asset,
          //       width: context.width,
          //       height: context.height,
          //     ),
          //     fit: BoxFit.contain,
          //     height: context.height,
          //     width: context.width,
          //     alignment: Alignment.center,
          //   ),
          // ),
          child: VideoViewerPage(
            key: getVideoPlayerKey(asset.id),
            asset: asset,
            isMotionVideo: asset.livePhotoVideoId != null,
            loopVideo: asset.livePhotoVideoId != null ? false : shouldLoopVideo.value,
            placeholder: Image(
              image: ImmichImage.imageProvider(
                asset: asset,
                width: asset.width!.toDouble(),
                height: asset.height!.toDouble(),
              ),
              fit: BoxFit.contain,
              height: context.height,
              width: context.width,
              alignment: Alignment.center,
            ),
          ),
        ),
      );
    }

    PhotoViewGalleryPageOptions buildAsset(BuildContext context, int index) {
      var newAsset = loadAsset(index);

      final stackId = newAsset.stackId;
      if (stackId != null && currentIndex.value == index) {
        final stackElements = ref.read(assetStackStateProvider(newAsset.stackId!));
        if (stackIndex.value < stackElements.length) {
          newAsset = stackElements.elementAt(stackIndex.value);
        }
      }

      if (newAsset.isImage && !isPlayingMotionVideo) {
        if (lastPlayingState == 1) {
          if (imageHdrState == 1) {
            ui.SetHdr.setHdrMode(hdr: 1, is_image: true);
          }
          if (imageHdrState == 0) {
            ui.SetHdr.setHdrMode(hdr: 0, is_image: true);
          }
        }
        lastPlayingState = 0;
        return buildImage(newAsset);
      }
      return buildVideo(context, newAsset);
    }

    return PopScope(
      // Change immersive mode back to normal "edgeToEdge" mode
      onPopInvokedWithResult: (didPop, _) {
        if (didPop) {
          SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
        }
        cancelAllTimers();
      },
      child: Scaffold(
        backgroundColor: Colors.black,
        body: Stack(
          children: [
            PhotoViewGallery.builder(
              key: const ValueKey('gallery'),
              scaleStateChangedCallback: (state) {
                final asset = ref.read(currentAssetProvider);
                if (asset == null) {
                  return;
                }

                //if (asset.isImage && !ref.read(isPlayingMotionVideoProvider)) {
                if (asset.isImage && !isPlayingMotionVideo) {
                  if (lastPlayingState == 1) {
                    if (imageHdrState == 1) {
                      ui.SetHdr.setHdrMode(hdr: 1, is_image: true);
                    }
                    if (imageHdrState == 0) {
                      ui.SetHdr.setHdrMode(hdr: 0, is_image: true);
                    }
                  }
                  lastPlayingState = 0;
                  isZoomed.value = state != PhotoViewScaleState.initial;
                  ref.read(showControlsProvider.notifier).show = !isZoomed.value;
                }
              },
              gaplessPlayback: true,
              loadingBuilder: (context, event, index) {
                final asset = loadAsset(index);
                return ClipRect(
                  child: Stack(
                    fit: StackFit.expand,
                    children: [
                      BackdropFilter(filter: ui.ImageFilter.blur(sigmaX: 10, sigmaY: 10)),
                      ImmichThumbnail(key: ValueKey(asset), asset: asset, fit: BoxFit.contain),
                    ],
                  ),
                );
              },
              pageController: controller,
              scrollPhysics: isZoomed.value
                  ? const NeverScrollableScrollPhysics() // Don't allow paging while scrolled in
                  : (Platform.isIOS
                        ? const FastScrollPhysics() // Use bouncing physics for iOS
                        : const FastScrollPhysics() // Use heavy physics for Android
                          ),
              itemCount: totalAssets.value,
              scrollDirection: Axis.horizontal,
              onPageChanged: (value, _) {
                ref.read(isPlayingMotionVideoProvider.notifier).playing = false;

                final next = currentIndex.value < value ? value + 1 : value - 1;

                ref.read(hapticFeedbackProvider.notifier).selectionClick();

                final newAsset = loadAsset(value);

                currentIndex.value = value;
                stackIndex.value = 0;

                ref.read(currentAssetProvider.notifier).set(newAsset);
                if (newAsset.isVideo || newAsset.isMotionPhoto) {
                  ref.read(videoPlaybackValueProvider.notifier).reset();
                }

                final a = loadAsset(currentIndex.value);
                final ImageProvider provider = ImmichImage.imageProvider(asset: a);

                if (a.isImage) {
                  lastPlayingState = 0;
                  imageHdrState = -1;
                  setDisplayMode(provider, context);
                } else {
                  ui.SetHdr.setHdrMode(hdr: 0, is_image: true);
                }

                // Then precache the next image

                // Wait for page change animation to finish, then precache the next image
                timers.value.add(
                  Timer(const Duration(milliseconds: 400), () {
                    if (!a.isImage) {
                      ui.SetHdr.setHdrMode(hdr: -1, is_image: false);
                    }
                    precacheNextImage(next);
                  }),
                );
                /*
                context.scaffoldMessenger.hideCurrentSnackBar();

                // send image to casting if the server has it
                if (newAsset.isRemote) {
                  ref.read(castProvider.notifier).loadMediaOld(newAsset, false);
                } else {
                  context.scaffoldMessenger.clearSnackBars();

                if (isCasting) {
                  ref.read(castProvider.notifier).stop();
                  context.scaffoldMessenger.showSnackBar(
                    SnackBar(
                      duration: const Duration(seconds: 2),
                      content: Text(
                        "local_asset_cast_failed".tr(),
                        style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor),
                      ),
                    ),
                  );
                }
                }
*/
              },
              builder: buildAsset,
            ),
            Positioned(
              top: 0,
              left: 0,
              right: 0,
              child: GalleryAppBar(key: const ValueKey('app-bar'), showInfo: showInfo),
            ),
            Positioned(
              bottom: 0,
              left: 0,
              right: 0,
              child: Column(
                children: [
                  GalleryStackedChildren(stackIndex),
                  BottomGalleryBar(
                    key: const ValueKey('bottom-bar'),
                    renderList: renderList,
                    totalAssets: totalAssets,
                    controller: controller,
                    showStack: showStack,
                    stackIndex: stackIndex,
                    assetIndex: currentIndex,
                  ),
                ],
              ),
            ),
            const DownloadPanel(),
          ],
        ),
      ),
    );
  }

  @pragma('vm:prefer-inline')
  PhotoViewHeroAttributes _getHeroAttributes(Asset asset) {
    return PhotoViewHeroAttributes(
      tag: asset.isInDb ? asset.id + heroOffset : '${asset.remoteId}-$heroOffset',
      transitionOnUserGestures: true,
    );
  }
}

class _MyRouteAware extends RouteAware {
  //@override
  // void didPopNext() {
  //   super.didPopNext();
  //   ui.SetHdr.setHdrMode(hdr: 0, is_image: true);
  // }
  // void didPush() { }

  @override
  void didPop() {
    ui.SetHdr.setHdrMode(hdr: 0, is_image: true);
    super.didPop();
  }

  // void didPushNext() { }
}
